async function createOrderCallback() {
    try {
      const response = await fetch("/index/pay/orders", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        // use the "body" param to optionally pass additional order information
        // like product ids and quantities
        body: JSON.stringify({
          cart: [
            {
              id: "YOUR_PRODUCT_ID",
              quantity: "YOUR_PRODUCT_QUANTITY",
            },
          ],
        }),
      });
  
      const orderData = await response.json();
  
      if (orderData.id) {
        return orderData.id;
      } else {
        const errorDetail = orderData?.details?.[0];
        const errorMessage = errorDetail
          ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})`
          : JSON.stringify(orderData);
  
        throw new Error(errorMessage);
      }
    } catch (error) {
      console.error(error);
      resultMessage(`Could not initiate PayPal Checkout...<br><br>${error}`);
    }
  }
  
  async function onApproveCallback(data, actions) {
    try {
      //3DS验证
      const {liabilityShift, orderID} = data;
      console.log('3DS-'+ liabilityShift);
      if (liabilityShift && liabilityShift !== 'POSSIBLE') {
        //NO：责任由商家承担。不要继续授权；UNKNOWN：身份验证系统不可用,不要继续授权。要求持卡人重试
        resultMessage(`3DS Secure Unsuccessful`);
        return false;
      }
      const response = await fetch(`/index/pay/capture/${data.orderID}/capture`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
      });
  
      const orderData = await response.json();
      // Three cases to handle:
      //   (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
      //   (2) Other non-recoverable errors -> Show a failure message
      //   (3) Successful transaction -> Show confirmation or thank you message
  
      const transaction =
        orderData?.purchase_units?.[0]?.payments?.captures?.[0] ||
        orderData?.purchase_units?.[0]?.payments?.authorizations?.[0];
      const errorDetail = orderData?.details?.[0];
  
      // this actions.restart() behavior only applies to the Buttons component
      if (errorDetail?.issue === "INSTRUMENT_DECLINED" && !data.card && actions) {
        // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
        // recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/
        return actions.restart();
      } else if (
        errorDetail ||
        !transaction ||
        transaction.status === "DECLINED"
      ) {
        // (2) Other non-recoverable errors -> Show a failure message
        let errorMessage;
        if (transaction) {
          errorMessage = `Transaction ${transaction.status}: ${transaction.id}`;
        } else if (errorDetail) {
          errorMessage = `${errorDetail.description} (${orderData.debug_id})`;
        } else {
          errorMessage = JSON.stringify(orderData);
        }
  
        throw new Error(errorMessage);
      } else {
        // (3) Successful transaction -> Show confirmation or thank you message
        // Or go to another URL:  actions.redirect('thank_you.html');
        resultMessage(
          `Transaction ${transaction.status}: ${transaction.id}<br><br>See console for all available details`,
        );
        console.log(
          "Capture result",
          orderData,
          JSON.stringify(orderData, null, 2),
        );
      }
    } catch (error) {
      console.error(error);
      resultMessage(
        `Sorry, your transaction could not be processed...<br><br>${error}`,
      );
    }
  }
  
  window.paypal
    .Buttons({
      createOrder: createOrderCallback,
      onApprove: onApproveCallback,
    })
    .render("#paypal-button-container");
  
  const cardField = window.paypal.CardFields({
    createOrder: createOrderCallback,
    onApprove: onApproveCallback,
  });
  
  // Render each field after checking for eligibility
  if (cardField.isEligible()) {
    const nameField = cardField.NameField();
    nameField.render("#card-name-field-container");
  
    const numberField = cardField.NumberField();
    numberField.render("#card-number-field-container");
  
    const cvvField = cardField.CVVField();
    cvvField.render("#card-cvv-field-container");
  
    const expiryField = cardField.ExpiryField();
    expiryField.render("#card-expiry-field-container");
  
    // Add click listener to submit button and call the submit function on the CardField component
    document
      .getElementById("card-field-submit-button")
      .addEventListener("click", () => {
        cardField
          .submit({
            // From your billing address fields
            billingAddress: {
              addressLine1: document.getElementById("card-billing-address-line-1")
                .value,
              addressLine2: document.getElementById("card-billing-address-line-2")
                .value,
              adminArea1: document.getElementById(
                "card-billing-address-admin-area-line-1",
              ).value,
              adminArea2: document.getElementById(
                "card-billing-address-admin-area-line-2",
              ).value,
              countryCode: document.getElementById(
                "card-billing-address-country-code",
              ).value,
              postalCode: document.getElementById(
                "card-billing-address-postal-code",
              ).value,
            },
          })
          .catch((error) => {
            resultMessage(
              `Sorry, your transaction could not be processed...<br><br>${error}`,
            );
          });
      });
  } else {
    // Hides card fields if the merchant isn't eligible
    document.querySelector("#card-form").style = "display: none";
  }
  
  // Example function to show a result to the user. Your site's UI library can be used instead.
  function resultMessage(message) {
    const container = document.querySelector("#result-message");
    container.innerHTML = message;
  }
  